package com.runjian.rundo.iot.agent.iec104.action.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import com.runjian.rundo.bmp.kernel.common.spring.context.utils.MdcUtils;
import com.runjian.rundo.iot.agent.common.entity.AgentDeviceDTO;
import com.runjian.rundo.iot.agent.common.message.DecodedMessage;
import com.runjian.rundo.iot.agent.common.message.DeviceMessage;
import com.runjian.rundo.iot.agent.iec104.consts.DeviceType;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import com.runjian.rundo.iot.agent.common.thread.ScheduledExecutorFactory;
import com.runjian.rundo.iot.agent.iec104.action.AbstractActionHandle;
import com.runjian.rundo.iot.agent.iec104.cache.ScheduleTaskCache;
import com.runjian.rundo.iot.agent.iec104.config.Iec104Properties;
import com.runjian.rundo.iot.agent.iec104.consts.Action;
import com.runjian.rundo.iot.agent.iec104.consts.Ti;
import com.runjian.rundo.iot.agent.iec104.manager.Iec104DeviceManager;
import com.runjian.rundo.iot.agent.iec104.module.Iec104Device;
import com.runjian.rundo.iot.agent.iec104.parser.ASDUParser;
import com.runjian.rundo.iot.agent.iec104.parser.frame.IIec104Frame;
import com.runjian.rundo.iot.agent.iec104.session.Iec104TcpClientDeviceSession;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 总召唤动作实现
 *
 * @author CaoQingHua
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class SummoningActionHandle extends AbstractActionHandle {

    private final ScheduledExecutorFactory taskScheduledExecutorFactory;

    private final Iec104DeviceManager deviceManager;

    private final ASDUParser asduParser;

    private final Iec104Properties iec104Properties;

    private final ScheduleTaskCache scheduleTaskCache;

    @Override
    public Action getAction() {
        return Action.SCHEDULED_C_IC_NA_1;
    }

    @Override
    public void handle(DeviceMessage deviceMessage,Iec104TcpClientDeviceSession iec104DeviceSession) {
        if (null != scheduleTaskCache.getChannelFuture(iec104DeviceSession.getChannel(), this.getAction())) {
            if (log.isDebugEnabled()) {
                log.debug("定时总召任务已存在,当前管道Id:{}", iec104DeviceSession.getChannelId());
            }
            return;
        }
        Future future = this.taskScheduledExecutorFactory.addScheduleAtFixedRate(() -> {
            try {
                // 全量召唤
                List<AgentDeviceDTO> deviceMap = deviceManager.getDeviceMap(iec104DeviceSession.getId(), DeviceType.A.getCode());
                // 发起全量总召唤
                log.info("开始定时总召");
                deviceMap.forEach(e -> {
                    Iec104Device iec104Device=(Iec104Device)e;
                    IIec104Frame iIec104FrameFor100 = asduParser.iIec104Frame(Ti.C_IC_NA_1, Short.valueOf(iec104Device.getAddress()));
                    log.info("总召类型 100");
                    iec104DeviceSession.writeIAndFlush(iIec104FrameFor100);
                    Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
                    // 添加30秒延迟任务执行101类型总召
                    taskScheduledExecutorFactory.addSchedule(() -> {
                        MdcUtils.setTraceId(copyOfContextMap.get("traceId"));
                        IIec104Frame iIec104FrameFor101 = asduParser.iIec104Frame(Ti.C_CI_NA_1, Short.valueOf(iec104Device.getAddress()));
                        log.info("总召类型 101（延迟30秒后执行）");
                        iec104DeviceSession.writeIAndFlush(iIec104FrameFor101);
                    }, 30, TimeUnit.SECONDS);
                });
            } catch (Exception e) {
                // 全量召唤出错
                log.error("定时总召换执行异常,", e);
            }
        }, 0, iec104Properties.getSummoningInterval(), TimeUnit.SECONDS);
        // 保存好任保，以便后面取消
        scheduleTaskCache.putChannelFuture(iec104DeviceSession.getChannel(), this.getAction(), future);
    }


    @Deprecated
    public void handleDeprecated(DeviceMessage deviceMessage,Iec104TcpClientDeviceSession iec104DeviceSession) {
        //保存需要的数据
        Map<Action,List<String>> currentActionData= this.scheduleTaskCache.getChannelData(iec104DeviceSession.getChannel());
        List<String> devices=currentActionData.getOrDefault(this.getAction(),new ArrayList<>());
        if(ObjUtil.isNotNull(deviceMessage)){
            if(ObjectUtil.isNotEmpty(deviceMessage.getDecodedMessages())){
                deviceMessage.getDecodedMessages().forEach(e->{
                    if(!devices.contains(e.getDeviceId())) {
                        devices.add(e.getDeviceId());
                    }
                });
            }
        }
        if (null != scheduleTaskCache.getChannelFuture(iec104DeviceSession.getChannel(), this.getAction())) {
            if (log.isDebugEnabled()) {
                log.debug("定时总召任务已存在,当前管道Id:{}", iec104DeviceSession.getChannelId());
            }
            return;
        }
        Future future = this.taskScheduledExecutorFactory.addScheduleAtFixedRate(() -> {
            try {
                devices.forEach(e->{
                    Iec104Device iec104Device=deviceManager.getDeviceById(e);
                    // 全量召唤
                    IIec104Frame iIec104Frame = asduParser.iIec104Frame(Ti.C_IC_NA_1, Short.valueOf(iec104Device.getAddress()));
                    // 获取
                    iec104DeviceSession.writeIAndFlush(iIec104Frame);
                });
            } catch (Exception e) {
                // 全量召唤出错
                log.error("定时总召换执行异常,", e);
            }
        }, 0, iec104Properties.getSummoningInterval(), TimeUnit.SECONDS);
        // 保存好任保，以便后面取消
        scheduleTaskCache.putChannelFuture(iec104DeviceSession.getChannel(), this.getAction(), future);
    }

}
